import PRQuadtree.Point;
import PRQuadtree.PrQuadTree;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;


// On my honor:
//
// - I have not used source code obtained from another student,
// or any other unauthorized source, either modified or
// unmodified.
//
// - All source code and documentation used in my program is
// either my original work, or was derived by me from the
// source code published in the textbook for this course.
//
// - I have not discussed coding details about this project with
// anyone other than my partner (in the case of a joint
// submission), instructor, ACM/UPE tutors or the TAs assigned
// to this course. I understand that I may discuss the concepts
// of this program with other students, and that another student
// may help me debug my program so long as neither of us writes
// anything during the discussion or modifies any computer file
// during the discussion. I have violated neither the spirit nor
// letter of this restriction.
/**
 * @author Semere Sium (dfoster0) Xavier Seymour (xaviers3)
 * @version 2011.10.04
 */

public class prprog
{

    public static void main( String[] args )
        throws IOException
    {

        String myInputFile =
            "/Users/Xavier/workspaceSOPH/Project2_3114/src/p2SyntaxTest.txt";
        File commandFile = null;

        if ( args.length == 2 )
        {
            //GLOBAL VARIABLES
            commandFile = new File( args[1] );
            // This tree represents the BST we will use to quick search by name
            // for a cityRecord
            BST<String, CityRecord> nameBST = new BST<String, CityRecord>();
            int max = 2;
            max = (int)Math.pow( 2, 14 );
            PrQuadTree<Point> quadTree = new PrQuadTree(0, max, 0, max );

            try
            {

                // Open File
                FileInputStream fileStream = new FileInputStream( myInputFile );
                // Get the object of DataInputStream
                DataInputStream input = new DataInputStream( fileStream );
                BufferedReader bufferReader =
                    new BufferedReader( new InputStreamReader( input ) );
                String strLine;

                // Read File Line By Line
                while ( ( strLine = bufferReader.readLine() ) != null )
                {

                    strLine = strLine.trim(); // Remove leading and ending
                    // whitespaces
                    strLine = strLine.replaceAll( "\\s+", " " ); // Remove extra
                    // whitespaces
                    // between
                    // params

                    // LINE BY LINE MANIPULATION OF DATA------------------------------------------
                    if ( !strLine.isEmpty() ) // Ignore empty spaces
                    {
                        // Print the content on the console
                         System.out.println (strLine);
                        String[] currCommand = strLine.split( "\\s+" );



                        if ( currCommand[0].equals( "insert" ) )
                        {
                            // INSERT LOGIC-------------------Complete----------------------------
                            int x = Integer.parseInt(currCommand[1]);
                            int y = Integer.parseInt(currCommand[2]);
                            String errorMessage = "";
                            CityRecord record = new CityRecord(currCommand[3],
                                x, y);
                            //INSERT THE RECORD INTO THE PRQUADTREE-------------------------------
                            boolean canInsert = true;
                            Point p = new Point(record.getXCoordinate(), record.getYCoordinate());
                            Point isFound = quadTree.find( p );
                            if(isFound == null) { //this value will dictate whether or not we can insert the record into the nameBST
                                                  //and the PRQuadTree
                            quadTree.insert( new Point(record.getXCoordinate(), record.getYCoordinate()));



                            }else{
                            canInsert = false;
                            errorMessage = ">> Insert rejected, coordinates " +
                                        "duplicate an existing city record";
                            }

                            if(x < 0 || x >= Math.pow( 2, 14 )) {
                                canInsert = false;
                                errorMessage = ">> Insert rejected, bad X coordinate";
                            }
                            else if(y < 0 || y >= Math.pow( 2, 14 )) {
                                canInsert = false;
                                errorMessage = ">> Insert rejected, bad Y coordinate";
                            }



                            //INSERT THE RECORD INTO THE BST---------------------------------------

                            //insert the record into the BST if it can be inserted
                            if(canInsert) {
                                //Temporary method recordExists---------------------
                            if(!recordExists(nameBST.getRoot(), record)) {
                            nameBST.insert( record.getCityName(), record );
                            System.out.println(">> Insert operation successful");
                            System.out.println();
                            }else {
                                System.out.println(">> Insert rejected, coordinates " +
                                		"duplicate an existing city record");
                                System.out.println();
                            }
                        }else {
                            System.out.println(errorMessage);
                            System.out.println();
                            }
                        }

                        else if ( currCommand[0].equals( "remove" ) )
                        {
                            // REMOVE LOGIC-------------------------------------------------------
                            if ( getRemoveType( currCommand ) == true )
                            {
                                // REMOVE BY NAME-----------------Complete----------------------
                                     // REMOVE FROM BST-----------------------------------------
                                //The string to be removed
                                String toRemove = currCommand[1];
                                CityRecord record = nameBST.remove( toRemove );
                                //A record was removed
                                if(record != null) {
                                     //REMOVE FROM QUAD TREE--------------------------------
                                    Point p = new Point(record.getXCoordinate(), record.getYCoordinate());
                                    quadTree.delete( p );

                                    //Print out the appropriate message
                                   System.out.println(">> Removed "+ record.getXCoordinate()
                                       + ", "+ record.getYCoordinate()+ ", "+ record.getCityName());
                                   System.out.println();
                                }
                                //A record was not removed
                                else {
                                    System.out.println(">> No such City Record found");
                                    System.out.println();
                                }


                            }else
                            {
                                // REMOVE BY COORDINATE------------------------------------------
                                int x = Integer.parseInt(currCommand[1]);
                                int y = Integer.parseInt(currCommand[2]);
                                Point p = new Point(x, y);
                                String errorMessage = "";
                                boolean canRemove = true;
                                CityRecord recordRemoved = new CityRecord();


                                //Remove the point from the quadTree if it exists, and
                                //set canRemove to the outcome of the removal procedure
                                recordRemoved = quadTree.delete( p );
                                if(recordRemove == null) {
                                    canRemove = false;
                                }
                                if(!canRemove) {
                                    errorMessage = ">> No such City Record found";
                                }

                                if(x < 0 || x >= Math.pow( 2, 14 )) {
                                    canRemove = false;
                                    errorMessage = ">> Remove operation failed: Bad X coordinate";
                                }
                                else if(y < 0 || y >= Math.pow( 2, 14 )) {
                                    canRemove = false;
                                    errorMessage = ">> Remove operation failed: Bad Y coordinate";
                                }


                                //Remove the record from the nameBST if it can be done---------
                                if(canRemove) {
                                 CityRecord r = nameBST.remove( recordRemoved.getCityName(), recordRemoved );

                                  // System.out.println(">> Removed "+ r.getXCoordinate()
                                  //          + ", "+ r.getYCoordinate()+ ", "+ r.getCityName());
                                  //      System.out.println();


                                   // System.out.println(">> Removed "+ recordRemoved.getXCoordinate()
                                   //     + ", "+ recordRemoved.getYCoordinate()+ ", "+ recordRemoved.getCityName());
                                   // System.out.println();
                                }else {
                                    System.out.println(errorMessage);
                                    System.out.println();
                                }
                            }
                        }



                        else if ( currCommand[0].equals( "find" ) )
                        {
                            // FIND LOGIC-------------------Complete-----------------------------
                            String toFind = currCommand[1];
                            System.out.println(">> City Records found:");
                            findAll(nameBST.getRoot(), toFind, 0);
                        }
                        else if ( currCommand[0].equals( "search" ) )
                        {
                            // SEARCH LOGIC------------------------------------------------------
                        }
                        else if ( currCommand[0].equals( "debug" ) )
                        {
                            // DEBUG LOGIC-------------------------------------------------------
                        }
                        else if ( currCommand[0].equals( "makenull" ) )
                        {
                            // MAKENULL LOGIC----------------------------------------------------
                            nameBST.clear();
                            //Clear PRQuadTree here---------------------
                            System.out.println(">> Makenull operation successful");
                            System.out.println();

                        }
                        System.out.println(nameBST.size());
                    }
                }
                // Close the input stream
                input.close();
                System.out.println(nameBST.size());
            }

            catch ( Exception e )
            { // Catch exception if any

                System.err.println( "Error: " + e.getMessage() );

            }

        }
        else
        {
            System.err.println( "Usage: java prprog <command-file>" );
            System.exit( 1 );
        }
    }


    // ----------------------------------------------------------
    /**
     * This method will be used to test what type of remove we are currently
     * attempting to perform, either by city name, or by coordinates
     *
     * @param str
     * @return
     */
    public static boolean getRemoveType( String[] str )
    {
        if ( str.length == 2 )
        {
            return true;
        }
        else
            return false;
    }


    public static boolean recordExists(
        BSTNode<String, CityRecord> rt,
        CityRecord record )
    {
        // if rt is null, the record is not in the tree
        if ( rt == null )
            return false;
        // if the record in question has a key value smaller than the current
        // node, move to the left
        if ( ( rt.key().compareTo( record.getCityName() ) > 0 ) )
        {
            return recordExists( rt.left(), record );
        }
        // if they match, return true
        else if ( ( rt.key().compareTo( record.getCityName() ) == 0 ) )
        {
            if ( rt.element().getXCoordinate() == record.getXCoordinate()
                && rt.element().getYCoordinate() == record.getYCoordinate() )
            {
                return true;
            }
        }
        // otherwise, move to the right
        else
        {
            return recordExists( rt.right(), record );

        }
        return false;

    }

    public static int findAll(BSTNode<String, CityRecord> rt, String toFind, int count) {
        if(rt == null) {
            if(count == 0) {
                System.out.println("No records");
                System.out.println();
                return count;
            }else {
                System.out.println();
                return count;
            }
        }
        if(rt.key().compareTo( toFind ) > 0)
            return findAll(rt.left(), toFind, count);
        else if(rt.key().compareTo( toFind ) == 0) { //found it
            System.out.println(rt.element().getXCoordinate()+ ", "+ rt.element().getYCoordinate()
                + ", "+ rt.element().getCityName());
            count++;
            return findAll(rt.right(), toFind, count);
        }
        else {
            return findAll(rt.right(), toFind, count);
        }
    }


}
